using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace XnaUtility.Camera
{
    public class CameraBase : GameComponent
    {
        #region "Properties"
        protected Matrix world;
        protected Matrix view;
        protected Matrix projection;
        protected float aspectRatio;
        protected float fov;
        public Vector3 Location;
        protected Vector3 target;
        protected float nearPlane;
        protected float farPlane;

        private Game game;
        protected Vector3 up;

        public float FarPlane
        {
            get { return farPlane; }
        }

        public float NearPlane
        {
            get { return nearPlane; }
        }

        public Vector3 Target
        {
            set { target = value; }
            get { return target; }
        }
	
	
        public float FoV
        {
            get { return fov; }
        }
	
        public float AspectRatio
        {
            get { return aspectRatio; }
        }
	
        public Matrix Projection
        {
            get { return projection; }
        }
	
        public Matrix View
        {
            get { return view; }
        }
	
        public Matrix World
        {
            get { return world; }
        }
	
        #endregion

        #region "Intializer and Constructors"

        /// <summary>
        /// Constructs a basic still camera
        /// </summary>
        /// <param name="game">Reference to the game</param>
        /// <param name="fov">The field of view in radians</param>
        /// <param name="ar">Aspect ratio of the screen</param>
        public CameraBase(Game game, float fov, float ar)
            : base(game)
        {
            this.fov = fov;
            aspectRatio = ar;
            this.game = game;
            Location = new Vector3(0, 0, 10);
            target = Vector3.Zero;
            nearPlane = 1.0f;
            farPlane = 10000.0f;
            up = Vector3.Up;
        }

        /// <summary>
        /// Constructs a basic still camera
        /// </summary>
        /// <param name="game">Reference to the game</param>
        /// <param name="fov">The field of view in radians</param>
        /// <param name="ar">Aspect ratio of the screen</param>
        /// <param name="near">Near plane</param>
        /// <param name="far">Far plane</param>
        public CameraBase(Game game, float fov, float ar, float near, float far)
            : base(game)
        {
            this.fov = fov;
            aspectRatio = ar;
            this.game = game;
            Location = new Vector3(0, 0, 10);
            target = Vector3.Zero;
            nearPlane = near;
            farPlane = far;
            up = Vector3.Up;
        }

        public override void Initialize()
        {
            

            world = Matrix.Identity;
            projection = Matrix.CreatePerspectiveFieldOfView(fov, aspectRatio, nearPlane, farPlane);
            view = Matrix.CreateLookAt(Location, target, up);

            base.Initialize();
        }

        #endregion

        #region "Methods that reset the projection"

        private void ResetProjection()
        {
            projection = Matrix.CreatePerspectiveFieldOfView(fov, aspectRatio, nearPlane, farPlane);
        }

        public void SetFieldOfView(float newFov)
        {
            fov = newFov;
            ResetProjection();
        }

        public void SetNearPlane(float newNearPlane)
        {
            nearPlane = newNearPlane;
            ResetProjection();
        }

        public void SetFarPlane(float newFarPlane)
        {
            farPlane = newFarPlane;
            ResetProjection();
        }

        public void SetAspectRatio(float newAr)
        {
            aspectRatio = newAr;
            ResetProjection();
        }

        #endregion

        public override void Update(GameTime gameTime)
        {
            Matrix.CreateLookAt(ref Location, ref target, ref up, out view);
            base.Update(gameTime);
        }
    }
}
